Das Ziel ist es, aus dem Datacamp Datensatz Soccer
Data, welcher Daten aus der höchsten englischen Fussballdivision
beinhaltet, folgende Fragestellung / Hypothese zu beantworten:
Die Manschaft, die zur Halbzeit vorne liegt, gewinnt mit einer
Chance von mindestens 75% das Spiel. Falls zur Halbzeit unentschieden
ist, gewinnt eher das Heimteam mit einer Chance von mindestens
33.4%.
Als Einführung werden wir auf Datacamp folgende Kurse durchgehen:
# Import libraries
library("plotly")
Loading required package: ggplot2
Attaching package: ‘plotly’
The following object is masked from ‘package:ggplot2’:
last_plot
The following object is masked from ‘package:stats’:
filter
The following object is masked from ‘package:graphics’:
layout
library("plyr")
Attaching package: ‘plyr’
The following objects are masked from ‘package:plotly’:
arrange, mutate, rename, summarise
library("dplyr")
Attaching package: ‘dplyr’
The following objects are masked from ‘package:plyr’:
arrange, count, desc, failwith, id, mutate, rename, summarise, summarize
The following objects are masked from ‘package:stats’:
filter, lag
The following objects are masked from ‘package:base’:
intersect, setdiff, setequal, union
library("forcats")
library("RColorBrewer")
Daten einlesen und Dataframe erstellen
# List files in folder "data"
files <- list.files(path="./data/", pattern=NULL, all.files=FALSE, full.names=TRUE)
# Create Dataframe with all csv from years 2015-2019
df <- ldply(.data = files, .fun = read.csv)
View(df)
Hier zählen wir, wie oft das Heim - und Auswärtsteam zur Halb - und
Vollzeit gewinnen oder ob das Spiel unentschieden ist.
A = Auswärtsteam gewinnt
D = Unentschieden
H = Heimteam gewinnt
# Create dataframe for halftime & fulltime results and count frequency
df_htr <- df %>% count(HTR)
df_ftr <- df %>% count(FTR)
# Halftime
df_htr
# Fulltime
df_ftr
# Create dataframe with halftime & fulltime result frequency
df_results <- data.frame(c("Away win", "Draw", "Home win"), c(df_htr$n), c(df_ftr$n))
# Rename column headers
col_headings <- c('Result','Halftime','Fulltime')
names(df_results) <- col_headings
df_results
In diesen beiden Dataframes sieht man deutlich, dass zur Halbzeit
meistens ein Unentschieden steht. Gegen Ende des Spiels, ist das
Unentschieden aber das seltenste Resultat. Knapp 700 mal von insgesamt
1520 Spielen siegte am Ende das Heimteam. Dies entspricht rund 46%. Wir
gehen davon aus, dass dies damit zu tun hat, dass beide Teams in der
zweiten Halbzeit mehr riskieren, da sie lieber den Sieg forcieren und
dabei eine Niederlage rauskommt, anstatt das Unentschieden über die Zeit
zu bringen.
# Plot grouped bar chart to visualize halftime & fulltime results
fig <- plot_ly(
df_results, x = ~Result, y = ~Halftime, type = 'bar', name = 'Halftime Score') %>%
add_trace(y = ~Fulltime, name = 'Fulltime Score') %>%
layout(yaxis = list(title = 'Amount'),
barmode = 'group',
width = 600, height = 500)
Warning: Specifying width/height in layout() is now deprecated.
Please specify in ggplotly() or plot_ly()
fig
Die obige Erkenntnis, haben wir hier noch als Barchart dargestellt.
Das Heimteam gewinnt also im Schnitt viel öfters, als das
Auswärtsteam.
# Merge HTR & FTR to new column 'result'
df$result <- paste(df$HTR, df$FTR)
# Example: H H = home team is winning at halftime and also wins the game at fulltime
df[,"result", drop=FALSE]
# Plot all different game progresses and their amount
df_count_results <- df %>%
count(result)
df_count_results %>%
mutate(result = fct_reorder(result, n, .desc = TRUE)) %>%
plot_ly(x = ~result, y = ~n, text = ~n, textposition = 'auto') %>%
add_bars() %>%
layout(xaxis = list(title = "Game Progress"),
yaxis = list(title = "Amount of Game Progresses"),
title = "How are the different game progresses distributed?",
width = 800, height = 500)
Warning: Specifying width/height in layout() is now deprecated.
Please specify in ggplotly() or plot_ly()
Hier wollten wir herausfinden, wie wahrscheinlich die 9 möglichen
Spielausgängen sind bevor das Spiel überhaupt beginnt. Man sieht, dass
der häufigste Spielverlauf das “HH” ist. Also, dass in den meisten
Spielen das Heimteam zur Halbzeit führt und die Führung bis zum schluss
halten kann. Das seltenste Resultat war, dass das Heimteam zur Pause
geführt hat und das Spiel am Ende doch noch verlor. Das kam bei 1520
Speielen nur genau 27x vor.
# Group by game outcome & calculate probability of all outcomes
df_count_results_prob <- df %>%
group_by(result) %>%
summarise(count_result = round(n() / nrow(df) * 100, digits = 2))
# Plot all different game progresses and their probability
df_count_results_prob %>%
mutate(result = fct_reorder(result, count_result, .desc = TRUE)) %>%
plot_ly(x = ~result, y = ~count_result, text = ~count_result, textposition = 'auto') %>%
add_bars() %>%
layout(xaxis = list(title = "Game Progress"),
yaxis = list(title = "Probability of Game Progress (%)"),
title = "How are the different game progresses distributed?",
width = 800, height = 500)
Warning: Specifying width/height in layout() is now deprecated.
Please specify in ggplotly() or plot_ly()
Den selben Graphen wollten wir noch in Prozenten darstellen.
# Group by game outcome & calculate probability of all outcomes
df_count_results <- df %>%
group_by(result) %>%
summarise(count_result = round(n() / nrow(df) * 100, digits = 2))
df_count_results %>%
plot_ly(labels = ~result, values = ~count_result) %>%
add_pie(hole = 0.4, color = I("white")) %>%
layout(xaxis = list(title = "Game Progress"),
yaxis = list(title = "Probability %"),
title = "What is the probability of each game progress?")
In diesem Donutchart sieht man die Verteilung nochmals anderst
dargestellt.
# Calculate probability between halftime & fulltime away / draw / home results
calc_prob <- function(df1, df2) {
prob <- round((100 / nrow(df1) * nrow(df2)), digits = 2)
return(prob)
}
# Filter home teams winning at halftime
df_ht_home <- df %>%
filter(HTR == "H")
# Filter home teams winning at halftime & fulltime
df_ft_home <- df_ht_home %>%
filter(FTR == "H")
home_win_prob <- calc_prob(df_ht_home, df_ft_home)
cat("Die Wahrscheinlichkeit, dass das Heimteam gewinnt, wenn sie zur Halbzeit vorne liegen, beträgt: ", home_win_prob, "%")
Die Wahrscheinlichkeit, dass das Heimteam gewinnt, wenn sie zur Halbzeit vorne liegen, beträgt: 82.55 %
# Filter away teams winning at halftime
df_ht_away <- df %>%
filter(HTR == "A")
# Filter away teams winning at halftime & fulltime
df_ft_away <- df_ht_away %>%
filter(FTR == "A")
away_win_prob <- calc_prob(df_ht_away, df_ft_away)
cat("Die Wahrscheinlichkeit, dass das Auswertsteam gewinnt, wenn sie zur Halbzeit vorne liegen, beträgt: ", away_win_prob, "%")
Die Wahrscheinlichkeit, dass das Auswertsteam gewinnt, wenn sie zur Halbzeit vorne liegen, beträgt: 72.03 %
# Filter draw at halftime
df_ht_draw <- df %>%
filter(HTR == "D")
# Filter draw at halftime & fulltime
df_ft_draw <- df_ht_draw %>%
filter(FTR == "D")
draw_prob <- calc_prob(df_ht_draw, df_ft_draw)
cat("Die Wahrscheinlichkeit, dass ein Spiel in einem Unentschieden endet, wenn schon zur Halbzeit unentschieden war, beträgt: ", draw_prob, "%")
Die Wahrscheinlichkeit, dass ein Spiel in einem Unentschieden endet, wenn schon zur Halbzeit unentschieden war, beträgt: 36.45 %
# Filter draw at halftime & the home team winning at fulltime
df_ht_draw_ft_home_win <- df_ht_draw %>%
filter(FTR == "H")
home_win_after_ht_draw_prob <- calc_prob(df_ht_draw, df_ht_draw_ft_home_win)
cat("Die Wahrscheinlichkeit, dass das Heimteam gewinnt, wenn zur Halbzeit unentschieden war, beträgt: ", home_win_after_ht_draw_prob, "%")
Die Wahrscheinlichkeit, dass das Heimteam gewinnt, wenn zur Halbzeit unentschieden war, beträgt: 38.03 %
Bestätigung der Hypothese
Nun wollen wir aber die Wahrscheinlichkeit wissen, dass das zur
Halbzeit führende Team das Spiel gewinnt. Egal ob Heim - oder
Auswärtsteam.
Somit können wir aus den 2 Wahrscheinlichkeiten “home_win_prob” und
“away_win_prob” unsere Hypothese wie folgt bestätigen:
# Probability that the team winning at half time wins the game
ht_ft_win_prob <- round(((home_win_prob * nrow(df_ft_home)) + (away_win_prob * nrow(df_ft_away))) / (nrow(df_ft_home) + nrow(df_ft_away)), digits = 2)
cat("Wahrscheinlichkeit, dass das Team, welches zur Halbzeit führt, den Match gewinnt: ", ht_ft_win_prob, "%")
Wahrscheinlichkeit, dass das Team, welches zur Halbzeit führt, den Match gewinnt: 78.41 %
fig <- plot_ly(
y = c("Home wins after leading at HT", "Away wins after leading at HT", "Draw at FT & HT"),
x = c(home_win_prob, away_win_prob, draw_prob),
type = "bar"
)
#label title and axis
fig <- fig %>% layout(title = "Game Progress Overview",
xaxis = list(title = "Probability"))
#print figure
fig
NA
Fazit
Wir konnten unsere Hypothese bestätigen. Das Team, welches zur
Halbzeit vorne liegt, gewinnt zu 78.41%. Ebenfalls ist die
Wahrscheinlichkeit, dass das Heimteam gewinnt, nach einem Unentschieden
zur Halbzeit, 38.03%. Wir hätten diesen Wert etwas höher erwartet und
sind über das Ergebnis überrascht.
2. Hypothese:
Das Heimteam hat mehr Schüsse als das Auswärtsteam, aber das
Auswertsteam ist effizienter.
# def variables
n_shots <- df %>%
summarise(
Home = sum(HS),
Away = sum(AS)
)
n_shots
Der erste Teil der Hypothese ist somit bestätigt. Die Heimteams haben
viel mehr schüsse aufs Tor. Im Durchschnitt sind es bei 1520 Spielen
also 14.01 Schüsse des Heimteams und 11.21 Schüsse des
Auswertsteams.
# Plot Fulltime Home Shots vs Home Goals
p1 <- df %>%
plot_ly(x = ~FTHG, y = ~HS, coloraxis = 'coloraxis') %>%
add_histogram2d(nbinsy = 40)
# Plot Fulltime Away Shots vs Away Goals
p2 <- df %>%
plot_ly(x = ~FTAG, y = ~AS, coloraxis = 'coloraxis') %>%
add_histogram2d(nbinsy = 40)
# Add both plots together to build subplot
subplot(p1, p2, nrows = 1, shareX = FALSE, shareY = FALSE) %>%
layout(
title = "Goals vs Shots Overview",
xaxis = list(title = "Home Goals"),
xaxis2 = list(title = "Away Goals"),
yaxis = list(title = "Home Shots"),
yaxis2 = list(title = "Away Shots"),
coloraxis=list(colorscale='Jet')
)
Anhand des Plots oben ist gut zu sehen, dass das Heimteam oftmals 1-2
Tore schiesst und 9-16 Torschüsse aufweist. Beim Auswärtsteam siehts
etwas anders aus; Sie schiessen eher 0-1 Tor und weisen dabei 6-11
Torschüsse auf.
# Fit the regression model of Fulltime Home Goals on Home Shots
m <- lm(FTHG ~ HS, data = df)
# Create the scatterplot with smoother
df %>%
plot_ly(x = ~HS, y = ~FTHG) %>%
add_markers(showlegend = FALSE) %>%
add_lines(y = ~fitted(m)) %>%
layout(title = "Expectet goals by home shots")
Auf diesem Plot, kann man anhand der orangen Linie sehen, wievielen
Tore man erwarten kann, bei einer gewissen Anzahl Schüsse des Heimteams.
Zum Beispiel: Wenn das Heimteam 25 Schüsse abgiebt, kann man im
Durchschnitt mit 2.310 Toren rechnen.
# Fit the regression model of Fulltime Away Goals on Away Shots
m <- lm(FTAG ~ AS, data = df)
# Create the scatterplot with smoother
df %>%
plot_ly(x = ~AS, y = ~FTAG) %>%
add_markers(showlegend = FALSE) %>%
add_lines(y = ~fitted(m)) %>%
layout(title = "Expectet goals by away shots")
Auf diesem Plot, kann man anhand der orangen Linie sehen, wievielen
Tore man erwarten kann, bei einer gewissen Anzahl Schüsse des
Auswertsteams. Zum Beispiel: Wenn das Auswertsteam 25 Schüsse abgiebt,
kann man im Durchschnitt mit 2.385 Toren rechnen.
df %>%
plot_ly(x = ~HS, y = ~AS, coloraxis = 'coloraxis') %>%
add_histogram2d(nbinsx = 70, nbinsy = 60) %>%
layout(coloraxis=list(colorscale='Jet'))
Anhand dieses Plots, sieht man die Verteilung der Schusshäufigkeit.
In den allermeisten Spielen, geben beide Teams 10-15 Schüsse ab. Es gibt
in seltenen Fällen aber auch Spiele, wo die Heimmanschaft viel, viel
mehr Schüsse hat. Zb 1x hatte das Heimteam 37 Schüsse und das
Auswertsteam NUR 3! Dieses Spiel war Liverpool : Everton im Jahr 2016
und Liverpool gewann 4:0.
#calculate the efficiency of the teams.
df_efficiency <- df %>%
summarise(
"Home Goals per Shot" = round(sum(FTHG) / sum(HS),digits = 3),
"Home Goals per Shot on Target" = round(sum(FTHG) / sum(HST),digits = 3),
"Away Goals per Shot" = round(sum(FTAG) / sum(AS),digits = 3),
"Away Goals per Shot on Target" = round(sum(FTAG) / sum(AST),digits = 3)
)
# Transpose dataframe
t_df_efficiency <- data.frame("Percent" = t(df_efficiency))
# Plot the efficiency in a barchart.
fig <- plot_ly(
y = c("Home Goals per Shot ", "Home Goals per Shot on Target ", "Away Goals per Shot ", "Away Goals per Shot on Target "),
x = t_df_efficiency$Percent,
type = "bar"
)
# Name the title
fig <- fig %>% layout(title = "Team Efficiency",
xaxis = list(title = "Probability"))
# Plot figure
fig
Anhand dieses Diagrams, kann man sehen, dass der zweite Teil unserer
Hypothese, leider nicht stimmt. Das Heimteam ist im Durchschnitt
effizienter als das Auswertsteam. Pro Schuss aufs Tor, kann das Heimteam
mit 0.328 Toren rechnen. Das Auswertsteam kann pro Torschuss nur mit
0.312 Toren rechnen.
Fazit
Wir sind überrascht, dass das Heimteam etwas effizienter ist, als das
Auswertsteam. Allerdings ist der Unterschied extrem knap. Was allerdings
spannend zu beobachten ist, ist dass das Heimteam im Schnitt ca. 14
Schüsse hat und das Auswertsteam nur ca. 11. Achtet euch doch beim
nächsten Fussballspiel darauf. Ihr könnt pro Spiel also mit ca. 25
Schüssen rechnen. Dabei ist es wahrscheinlich, dass das Heimteam das
Spiel gewinnt, auch wenn zur Halbzeit noch ein Unentschieden steht.
LS0tCnRpdGxlOiAiRGF0YSBWaXN1YWxpemF0aW9uIG1pdCBQbG90bHkiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCkRhcyBaaWVsIGlzdCBlcywgYXVzIGRlbSBEYXRhY2FtcCBEYXRlbnNhdHogW1NvY2NlciBEYXRhXShodHRwczovL2FwcC5kYXRhY2FtcC5jb20vd29ya3NwYWNlL2RhdGFzZXRzL2RhdGFzZXQtcHl0aG9uLXNvY2NlciksIHdlbGNoZXIgRGF0ZW4gYXVzIGRlciBow7ZjaHN0ZW4gZW5nbGlzY2hlbiBGdXNzYmFsbGRpdmlzaW9uIGJlaW5oYWx0ZXQsIGZvbGdlbmRlIEZyYWdlc3RlbGx1bmcgLyBIeXBvdGhlc2UgenUgYmVhbnR3b3J0ZW46CgoKIyMjIERpZSBNYW5zY2hhZnQsIGRpZSB6dXIgSGFsYnplaXQgdm9ybmUgbGllZ3QsIGdld2lubnQgbWl0IGVpbmVyIENoYW5jZSB2b24gbWluZGVzdGVucyA3NSUgZGFzIFNwaWVsLiBGYWxscyB6dXIgSGFsYnplaXQgdW5lbnRzY2hpZWRlbiBpc3QsIGdld2lubnQgZWhlciBkYXMgSGVpbXRlYW0gbWl0IGVpbmVyIENoYW5jZSB2b24gbWluZGVzdGVucyAzMy40JS4KCgpBbHMgRWluZsO8aHJ1bmcgd2VyZGVuIHdpciBhdWYgRGF0YWNhbXAgZm9sZ2VuZGUgS3Vyc2UgZHVyY2hnZWhlbjoKCi0gW0ludGVyYWN0aXZlIERhdGEgVmlzdWFsaXphdGlvbiB3aXRoIHBsb3RseV0oaHR0cHM6Ly9hcHAuZGF0YWNhbXAuY29tL2xlYXJuL2NvdXJzZXMvaW50ZXJhY3RpdmUtZGF0YS12aXN1YWxpemF0aW9uLXdpdGgtcGxvdGx5LWluLXIpCgotIFtJbnRlcm1lZGlhdGUgSW50ZXJhY3RpdmUgRGF0YSBWaXN1YWxpemF0aW9uIHdpdGggcGxvdGx5XShodHRwczovL2FwcC5kYXRhY2FtcC5jb20vbGVhcm4vY291cnNlcy9pbnRlcmFjdGl2ZS1kYXRhLXZpc3VhbGl6YXRpb24td2l0aC1wbG90bHktaW4tcikKCgpgYGB7cn0KIyBJbXBvcnQgbGlicmFyaWVzCmxpYnJhcnkoInBsb3RseSIpCmxpYnJhcnkoInBseXIiKQpsaWJyYXJ5KCJkcGx5ciIpCmxpYnJhcnkoImZvcmNhdHMiKQpsaWJyYXJ5KCJSQ29sb3JCcmV3ZXIiKQpgYGAKCiMjIyBEYXRlbiBlaW5sZXNlbiB1bmQgRGF0YWZyYW1lIGVyc3RlbGxlbgoKYGBge3J9CiMgTGlzdCBmaWxlcyBpbiBmb2xkZXIgImRhdGEiCmZpbGVzIDwtIGxpc3QuZmlsZXMocGF0aD0iLi9kYXRhLyIsIHBhdHRlcm49TlVMTCwgYWxsLmZpbGVzPUZBTFNFLCBmdWxsLm5hbWVzPVRSVUUpCgojIENyZWF0ZSBEYXRhZnJhbWUgd2l0aCBhbGwgY3N2IGZyb20geWVhcnMgMjAxNS0yMDE5CmRmIDwtIGxkcGx5KC5kYXRhID0gZmlsZXMsIC5mdW4gPSByZWFkLmNzdikKClZpZXcoZGYpCmBgYAoKSGllciB6w6RobGVuIHdpciwgd2llIG9mdCBkYXMgSGVpbSAtIHVuZCBBdXN3w6RydHN0ZWFtIHp1ciBIYWxiIC0gdW5kIFZvbGx6ZWl0IGdld2lubmVuIG9kZXIgb2IgZGFzIFNwaWVsIHVuZW50c2NoaWVkZW4gaXN0LgoKLSBBID0gQXVzd8OkcnRzdGVhbSBnZXdpbm50CgotIEQgPSBVbmVudHNjaGllZGVuCgotIEggPSBIZWltdGVhbSBnZXdpbm50CgpgYGB7cn0KIyBDcmVhdGUgZGF0YWZyYW1lIGZvciBoYWxmdGltZSAmIGZ1bGx0aW1lIHJlc3VsdHMgYW5kIGNvdW50IGZyZXF1ZW5jeSAKZGZfaHRyIDwtIGRmICU+JSBjb3VudChIVFIpCmRmX2Z0ciA8LSBkZiAlPiUgY291bnQoRlRSKQoKIyBIYWxmdGltZQpkZl9odHIKIyBGdWxsdGltZQpkZl9mdHIKYGBgCgpgYGB7cn0KIyBDcmVhdGUgZGF0YWZyYW1lIHdpdGggaGFsZnRpbWUgJiBmdWxsdGltZSByZXN1bHQgZnJlcXVlbmN5CmRmX3Jlc3VsdHMgPC0gZGF0YS5mcmFtZShjKCJBd2F5IHdpbiIsICJEcmF3IiwgIkhvbWUgd2luIiksIGMoZGZfaHRyJG4pLCBjKGRmX2Z0ciRuKSkKCiMgUmVuYW1lIGNvbHVtbiBoZWFkZXJzCmNvbF9oZWFkaW5ncyA8LSBjKCdSZXN1bHQnLCdIYWxmdGltZScsJ0Z1bGx0aW1lJykKbmFtZXMoZGZfcmVzdWx0cykgPC0gY29sX2hlYWRpbmdzCgpkZl9yZXN1bHRzCmBgYApJbiBkaWVzZW4gYmVpZGVuIERhdGFmcmFtZXMgc2llaHQgbWFuIGRldXRsaWNoLCBkYXNzIHp1ciBIYWxiemVpdCBtZWlzdGVucyBlaW4gVW5lbnRzY2hpZWRlbiBzdGVodC4gR2VnZW4gRW5kZSBkZXMgU3BpZWxzLCBpc3QgZGFzIFVuZW50c2NoaWVkZW4gYWJlciBkYXMgc2VsdGVuc3RlIFJlc3VsdGF0LiBLbmFwcCA3MDAgbWFsIHZvbiBpbnNnZXNhbXQgMTUyMCBTcGllbGVuIHNpZWd0ZSBhbSBFbmRlIGRhcyBIZWltdGVhbS4gRGllcyBlbnRzcHJpY2h0IHJ1bmQgNDYlLiBXaXIgZ2VoZW4gZGF2b24gYXVzLCBkYXNzIGRpZXMgZGFtaXQgenUgdHVuIGhhdCwgZGFzcyBiZWlkZSBUZWFtcyBpbiBkZXIgendlaXRlbiBIYWxiemVpdCBtZWhyIHJpc2tpZXJlbiwgZGEgc2llIGxpZWJlciBkZW4gU2llZyBmb3JjaWVyZW4gdW5kIGRhYmVpIGVpbmUgTmllZGVybGFnZSByYXVza29tbXQsIGFuc3RhdHQgZGFzIFVuZW50c2NoaWVkZW4gw7xiZXIgZGllIFplaXQgenUgYnJpbmdlbi4gCgpgYGB7cn0KIyBQbG90IGdyb3VwZWQgYmFyIGNoYXJ0IHRvIHZpc3VhbGl6ZSBoYWxmdGltZSAmIGZ1bGx0aW1lIHJlc3VsdHMKZmlnIDwtIHBsb3RfbHkoCiAgZGZfcmVzdWx0cywgeCA9IH5SZXN1bHQsIHkgPSB+SGFsZnRpbWUsIHR5cGUgPSAnYmFyJywgbmFtZSA9ICdIYWxmdGltZSBTY29yZScpICU+JSAKICBhZGRfdHJhY2UoeSA9IH5GdWxsdGltZSwgbmFtZSA9ICdGdWxsdGltZSBTY29yZScpICU+JQogIGxheW91dCh5YXhpcyA9IGxpc3QodGl0bGUgPSAnQW1vdW50JyksIAogICAgICAgICBiYXJtb2RlID0gJ2dyb3VwJywKICAgICAgICAgd2lkdGggPSA2MDAsIGhlaWdodCA9IDUwMCkKCmZpZwpgYGAKRGllIG9iaWdlIEVya2VubnRuaXMsIGhhYmVuIHdpciBoaWVyIG5vY2ggYWxzIEJhcmNoYXJ0IGRhcmdlc3RlbGx0LiBEYXMgSGVpbXRlYW0gZ2V3aW5udCBhbHNvIGltIFNjaG5pdHQgdmllbCDDtmZ0ZXJzLCBhbHMgZGFzIEF1c3fDpHJ0c3RlYW0uIAoKYGBge3J9CiMgTWVyZ2UgSFRSICYgRlRSIHRvIG5ldyBjb2x1bW4gJ3Jlc3VsdCcKZGYkcmVzdWx0IDwtIHBhc3RlKGRmJEhUUiwgZGYkRlRSKQoKIyBFeGFtcGxlOiBIIEggPSBob21lIHRlYW0gaXMgd2lubmluZyBhdCBoYWxmdGltZSBhbmQgYWxzbyB3aW5zIHRoZSBnYW1lIGF0IGZ1bGx0aW1lCgpkZlssInJlc3VsdCIsIGRyb3A9RkFMU0VdCmBgYAoKCmBgYHtyfQojIFBsb3QgYWxsIGRpZmZlcmVudCBnYW1lIHByb2dyZXNzZXMgYW5kIHRoZWlyIGFtb3VudApkZl9jb3VudF9yZXN1bHRzIDwtIGRmICU+JQogIGNvdW50KHJlc3VsdCkKICAKZGZfY291bnRfcmVzdWx0cyAlPiUKICBtdXRhdGUocmVzdWx0ID0gZmN0X3Jlb3JkZXIocmVzdWx0LCBuLCAuZGVzYyA9IFRSVUUpKSAlPiUKICBwbG90X2x5KHggPSB+cmVzdWx0LCB5ID0gfm4sIHRleHQgPSB+biwgdGV4dHBvc2l0aW9uID0gJ2F1dG8nKSAlPiUKICBhZGRfYmFycygpICU+JQogIGxheW91dCh4YXhpcyA9IGxpc3QodGl0bGUgPSAiR2FtZSBQcm9ncmVzcyIpLAogICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiQW1vdW50IG9mIEdhbWUgUHJvZ3Jlc3NlcyIpLAogICAgICAgICB0aXRsZSA9ICJIb3cgYXJlIHRoZSBkaWZmZXJlbnQgZ2FtZSBwcm9ncmVzc2VzIGRpc3RyaWJ1dGVkPyIsCiAgICAgICAgIHdpZHRoID0gODAwLCBoZWlnaHQgPSA1MDApCmBgYAoKSGllciB3b2xsdGVuIHdpciBoZXJhdXNmaW5kZW4sIHdpZSB3YWhyc2NoZWlubGljaCBkaWUgOSBtw7ZnbGljaGVuIFNwaWVsYXVzZ8OkbmdlbiBzaW5kIGJldm9yIGRhcyBTcGllbCDDvGJlcmhhdXB0IGJlZ2lubnQuIE1hbiBzaWVodCwgZGFzcyBkZXIgaMOkdWZpZ3N0ZSBTcGllbHZlcmxhdWYgZGFzICJISCIgaXN0LiBBbHNvLCBkYXNzIGluIGRlbiBtZWlzdGVuIFNwaWVsZW4gZGFzIEhlaW10ZWFtIHp1ciBIYWxiemVpdCBmw7xocnQgdW5kIGRpZSBGw7xocnVuZyBiaXMgenVtIHNjaGx1c3MgaGFsdGVuIGthbm4uIERhcyBzZWx0ZW5zdGUgUmVzdWx0YXQgd2FyLCBkYXNzIGRhcyBIZWltdGVhbSB6dXIgUGF1c2UgZ2Vmw7xocnQgaGF0IHVuZCBkYXMgU3BpZWwgYW0gRW5kZSBkb2NoIG5vY2ggdmVybG9yLiBEYXMga2FtIGJlaSAxNTIwIFNwZWllbGVuIG51ciBnZW5hdSAyN3ggdm9yLiAKCmBgYHtyfQojIEdyb3VwIGJ5IGdhbWUgb3V0Y29tZSAmIGNhbGN1bGF0ZSBwcm9iYWJpbGl0eSBvZiBhbGwgb3V0Y29tZXMKZGZfY291bnRfcmVzdWx0c19wcm9iIDwtIGRmICU+JSAKICBncm91cF9ieShyZXN1bHQpICU+JSAKICBzdW1tYXJpc2UoY291bnRfcmVzdWx0ID0gcm91bmQobigpIC8gbnJvdyhkZikgKiAxMDAsIGRpZ2l0cyA9IDIpKQoKIyBQbG90IGFsbCBkaWZmZXJlbnQgZ2FtZSBwcm9ncmVzc2VzIGFuZCB0aGVpciBwcm9iYWJpbGl0eQpkZl9jb3VudF9yZXN1bHRzX3Byb2IgJT4lCiAgbXV0YXRlKHJlc3VsdCA9IGZjdF9yZW9yZGVyKHJlc3VsdCwgY291bnRfcmVzdWx0LCAuZGVzYyA9IFRSVUUpKSAlPiUKICBwbG90X2x5KHggPSB+cmVzdWx0LCB5ID0gfmNvdW50X3Jlc3VsdCwgdGV4dCA9IH5jb3VudF9yZXN1bHQsIHRleHRwb3NpdGlvbiA9ICdhdXRvJykgJT4lCiAgYWRkX2JhcnMoKSAlPiUKICBsYXlvdXQoeGF4aXMgPSBsaXN0KHRpdGxlID0gIkdhbWUgUHJvZ3Jlc3MiKSwKICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIlByb2JhYmlsaXR5IG9mIEdhbWUgUHJvZ3Jlc3MgKCUpIiksCiAgICAgICAgIHRpdGxlID0gIkhvdyBhcmUgdGhlIGRpZmZlcmVudCBnYW1lIHByb2dyZXNzZXMgZGlzdHJpYnV0ZWQ/IiwKICAgICAgICAgd2lkdGggPSA4MDAsIGhlaWdodCA9IDUwMCkKYGBgCkRlbiBzZWxiZW4gR3JhcGhlbiB3b2xsdGVuIHdpciBub2NoIGluIFByb3plbnRlbiBkYXJzdGVsbGVuLiAKCmBgYHtyfQojIEdyb3VwIGJ5IGdhbWUgb3V0Y29tZSAmIGNhbGN1bGF0ZSBwcm9iYWJpbGl0eSBvZiBhbGwgb3V0Y29tZXMKZGZfY291bnRfcmVzdWx0cyA8LSBkZiAlPiUgCiAgZ3JvdXBfYnkocmVzdWx0KSAlPiUgCiAgc3VtbWFyaXNlKGNvdW50X3Jlc3VsdCA9IHJvdW5kKG4oKSAvIG5yb3coZGYpICogMTAwLCBkaWdpdHMgPSAyKSkKCmRmX2NvdW50X3Jlc3VsdHMgJT4lCiAgcGxvdF9seShsYWJlbHMgPSB+cmVzdWx0LCB2YWx1ZXMgPSB+Y291bnRfcmVzdWx0KSAlPiUKICBhZGRfcGllKGhvbGUgPSAwLjQsIGNvbG9yID0gSSgid2hpdGUiKSkgJT4lCiAgbGF5b3V0KHhheGlzID0gbGlzdCh0aXRsZSA9ICJHYW1lIFByb2dyZXNzIiksCiAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJQcm9iYWJpbGl0eSAlIiksCiAgICAgICAgIHRpdGxlID0gIldoYXQgaXMgdGhlIHByb2JhYmlsaXR5IG9mIGVhY2ggZ2FtZSBwcm9ncmVzcz8iKQpgYGAKSW4gZGllc2VtIERvbnV0Y2hhcnQgc2llaHQgbWFuIGRpZSBWZXJ0ZWlsdW5nIG5vY2htYWxzIGFuZGVyc3QgZGFyZ2VzdGVsbHQuIAoKYGBge3J9CiMgQ2FsY3VsYXRlIHByb2JhYmlsaXR5IGJldHdlZW4gaGFsZnRpbWUgJiBmdWxsdGltZSBhd2F5IC8gZHJhdyAvIGhvbWUgcmVzdWx0cwpjYWxjX3Byb2IgPC0gZnVuY3Rpb24oZGYxLCBkZjIpIHsKICBwcm9iIDwtIHJvdW5kKCgxMDAgLyBucm93KGRmMSkgKiBucm93KGRmMikpLCBkaWdpdHMgPSAyKQogIHJldHVybihwcm9iKQp9CmBgYAoKYGBge3J9CiMgRmlsdGVyIGhvbWUgdGVhbXMgd2lubmluZyBhdCBoYWxmdGltZQpkZl9odF9ob21lIDwtIGRmICU+JSAKICBmaWx0ZXIoSFRSID09ICJIIikKCiMgRmlsdGVyIGhvbWUgdGVhbXMgd2lubmluZyBhdCBoYWxmdGltZSAmIGZ1bGx0aW1lCmRmX2Z0X2hvbWUgPC0gZGZfaHRfaG9tZSAlPiUgCiAgZmlsdGVyKEZUUiA9PSAiSCIpCmhvbWVfd2luX3Byb2IgPC0gY2FsY19wcm9iKGRmX2h0X2hvbWUsIGRmX2Z0X2hvbWUpCgpjYXQoIkRpZSBXYWhyc2NoZWlubGljaGtlaXQsIGRhc3MgZGFzIEhlaW10ZWFtIGdld2lubnQsIHdlbm4gc2llIHp1ciBIYWxiemVpdCB2b3JuZSBsaWVnZW4sIGJldHLDpGd0OiAiLCBob21lX3dpbl9wcm9iLCAiJSIpCmBgYApgYGB7cn0KIyBGaWx0ZXIgYXdheSB0ZWFtcyB3aW5uaW5nIGF0IGhhbGZ0aW1lCmRmX2h0X2F3YXkgPC0gZGYgJT4lIAogIGZpbHRlcihIVFIgPT0gIkEiKQoKIyBGaWx0ZXIgYXdheSB0ZWFtcyB3aW5uaW5nIGF0IGhhbGZ0aW1lICYgZnVsbHRpbWUKZGZfZnRfYXdheSA8LSBkZl9odF9hd2F5ICU+JSAKICBmaWx0ZXIoRlRSID09ICJBIikKCmF3YXlfd2luX3Byb2IgPC0gY2FsY19wcm9iKGRmX2h0X2F3YXksIGRmX2Z0X2F3YXkpCgpjYXQoIkRpZSBXYWhyc2NoZWlubGljaGtlaXQsIGRhc3MgZGFzIEF1c3dlcnRzdGVhbSBnZXdpbm50LCB3ZW5uIHNpZSB6dXIgSGFsYnplaXQgdm9ybmUgbGllZ2VuLCBiZXRyw6RndDogIiwgYXdheV93aW5fcHJvYiwgIiUiKQpgYGAKCmBgYHtyfQojIEZpbHRlciBkcmF3IGF0IGhhbGZ0aW1lCmRmX2h0X2RyYXcgPC0gZGYgJT4lIAogIGZpbHRlcihIVFIgPT0gIkQiKQoKIyBGaWx0ZXIgZHJhdyBhdCBoYWxmdGltZSAmIGZ1bGx0aW1lCmRmX2Z0X2RyYXcgPC0gZGZfaHRfZHJhdyAlPiUgCiAgZmlsdGVyKEZUUiA9PSAiRCIpCgpkcmF3X3Byb2IgPC0gY2FsY19wcm9iKGRmX2h0X2RyYXcsIGRmX2Z0X2RyYXcpCgpjYXQoIkRpZSBXYWhyc2NoZWlubGljaGtlaXQsIGRhc3MgZWluIFNwaWVsIGluIGVpbmVtIFVuZW50c2NoaWVkZW4gZW5kZXQsIHdlbm4gc2Nob24genVyIEhhbGJ6ZWl0IHVuZW50c2NoaWVkZW4gd2FyLCBiZXRyw6RndDogIiwgZHJhd19wcm9iLCAiJSIpCmBgYAoKYGBge3J9CiMgRmlsdGVyIGRyYXcgYXQgaGFsZnRpbWUgJiB0aGUgaG9tZSB0ZWFtIHdpbm5pbmcgYXQgZnVsbHRpbWUKZGZfaHRfZHJhd19mdF9ob21lX3dpbiA8LSBkZl9odF9kcmF3ICU+JQogIGZpbHRlcihGVFIgPT0gIkgiKQoKaG9tZV93aW5fYWZ0ZXJfaHRfZHJhd19wcm9iIDwtIGNhbGNfcHJvYihkZl9odF9kcmF3LCBkZl9odF9kcmF3X2Z0X2hvbWVfd2luKQoKY2F0KCJEaWUgV2FocnNjaGVpbmxpY2hrZWl0LCBkYXNzIGRhcyBIZWltdGVhbSBnZXdpbm50LCB3ZW5uIHp1ciBIYWxiemVpdCB1bmVudHNjaGllZGVuIHdhciwgYmV0csOkZ3Q6ICIsIGhvbWVfd2luX2FmdGVyX2h0X2RyYXdfcHJvYiwgIiUiKQpgYGAKIyMjIEJlc3TDpHRpZ3VuZyBkZXIgSHlwb3RoZXNlCgpOdW4gd29sbGVuIHdpciBhYmVyIGRpZSBXYWhyc2NoZWlubGljaGtlaXQgd2lzc2VuLCBkYXNzIGRhcyB6dXIgSGFsYnplaXQgZsO8aHJlbmRlIFRlYW0gZGFzIFNwaWVsIGdld2lubnQuIEVnYWwgb2IgSGVpbSAtIG9kZXIgQXVzd8OkcnRzdGVhbS4KClNvbWl0IGvDtm5uZW4gd2lyIGF1cyBkZW4gMiBXYWhyc2NoZWlubGljaGtlaXRlbiAiaG9tZV93aW5fcHJvYiIgdW5kICJhd2F5X3dpbl9wcm9iIiB1bnNlcmUgSHlwb3RoZXNlIHdpZSBmb2xndCBiZXN0w6R0aWdlbjogCgpgYGB7cn0KIyBQcm9iYWJpbGl0eSB0aGF0IHRoZSB0ZWFtIHdpbm5pbmcgYXQgaGFsZiB0aW1lIHdpbnMgdGhlIGdhbWUKaHRfZnRfd2luX3Byb2IgPC0gcm91bmQoKChob21lX3dpbl9wcm9iICogbnJvdyhkZl9mdF9ob21lKSkgKyAoYXdheV93aW5fcHJvYiAqIG5yb3coZGZfZnRfYXdheSkpKSAvIChucm93KGRmX2Z0X2hvbWUpICsgbnJvdyhkZl9mdF9hd2F5KSksIGRpZ2l0cyA9IDIpCgpjYXQoIldhaHJzY2hlaW5saWNoa2VpdCwgZGFzcyBkYXMgVGVhbSwgd2VsY2hlcyB6dXIgSGFsYnplaXQgZsO8aHJ0LCBkZW4gTWF0Y2ggZ2V3aW5udDogIiwgaHRfZnRfd2luX3Byb2IsICIlIikKYGBgCgpgYGB7cn0KZmlnIDwtIHBsb3RfbHkoCiAgeSA9IGMoIkhvbWUgd2lucyBhZnRlciBsZWFkaW5nIGF0IEhUIiwgIkF3YXkgd2lucyBhZnRlciBsZWFkaW5nIGF0IEhUIiwgIkRyYXcgYXQgRlQgJiBIVCIpLCAKICB4ID0gYyhob21lX3dpbl9wcm9iLCBhd2F5X3dpbl9wcm9iLCBkcmF3X3Byb2IpLAogIHR5cGUgPSAiYmFyIgopCgojbGFiZWwgdGl0bGUgYW5kIGF4aXMKZmlnIDwtIGZpZyAlPiUgbGF5b3V0KHRpdGxlID0gIkdhbWUgUHJvZ3Jlc3MgT3ZlcnZpZXciLAogICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiUHJvYmFiaWxpdHkiKSkKCiNwcmludCBmaWd1cmUKZmlnCmBgYAojIyMgRmF6aXQKV2lyIGtvbm50ZW4gdW5zZXJlIEh5cG90aGVzZSBiZXN0w6R0aWdlbi4gRGFzIFRlYW0sIHdlbGNoZXMgenVyIEhhbGJ6ZWl0IHZvcm5lIGxpZWd0LCBnZXdpbm50IHp1IDc4LjQxJS4gRWJlbmZhbGxzIGlzdCBkaWUgV2FocnNjaGVpbmxpY2hrZWl0LCBkYXNzIGRhcyBIZWltdGVhbSBnZXdpbm50LCBuYWNoIGVpbmVtIFVuZW50c2NoaWVkZW4genVyIEhhbGJ6ZWl0LCAzOC4wMyUuIFdpciBow6R0dGVuIGRpZXNlbiBXZXJ0IGV0d2FzIGjDtmhlciBlcndhcnRldCB1bmQgc2luZCDDvGJlciBkYXMgRXJnZWJuaXMgw7xiZXJyYXNjaHQuIAoKCiMjIyAyLiBIeXBvdGhlc2U6CiMjIyBEYXMgSGVpbXRlYW0gaGF0IG1laHIgU2Now7xzc2UgYWxzIGRhcyBBdXN3w6RydHN0ZWFtLCBhYmVyIGRhcyBBdXN3ZXJ0c3RlYW0gaXN0IGVmZml6aWVudGVyLgoKYGBge3J9CiMgZGVmIHZhcmlhYmxlcwpuX3Nob3RzIDwtIGRmICU+JSAKICBzdW1tYXJpc2UoCiAgICBIb21lID0gc3VtKEhTKSwKICAgIEF3YXkgPSBzdW0oQVMpCikKCm5fc2hvdHMKYGBgCkRlciBlcnN0ZSBUZWlsIGRlciBIeXBvdGhlc2UgaXN0IHNvbWl0IGJlc3TDpHRpZ3QuIERpZSBIZWltdGVhbXMgaGFiZW4gdmllbCBtZWhyIHNjaMO8c3NlIGF1ZnMgVG9yLiBJbSBEdXJjaHNjaG5pdHQgc2luZCBlcyBiZWkgMTUyMCBTcGllbGVuIGFsc28gMTQuMDEgU2Now7xzc2UgZGVzIEhlaW10ZWFtcyB1bmQgMTEuMjEgU2Now7xzc2UgZGVzIEF1c3dlcnRzdGVhbXMuCgoKYGBge3J9CiMgUGxvdCBGdWxsdGltZSBIb21lIFNob3RzIHZzIEhvbWUgR29hbHMgCnAxIDwtIGRmICU+JQogIHBsb3RfbHkoeCA9IH5GVEhHLCB5ID0gfkhTLCBjb2xvcmF4aXMgPSAnY29sb3JheGlzJykgJT4lCiAgYWRkX2hpc3RvZ3JhbTJkKG5iaW5zeSA9IDQwKQoKIyBQbG90IEZ1bGx0aW1lIEF3YXkgU2hvdHMgdnMgQXdheSBHb2FscyAKcDIgPC0gZGYgJT4lCiAgcGxvdF9seSh4ID0gfkZUQUcsIHkgPSB+QVMsIGNvbG9yYXhpcyA9ICdjb2xvcmF4aXMnKSAlPiUKICBhZGRfaGlzdG9ncmFtMmQobmJpbnN5ID0gNDApCgojIEFkZCBib3RoIHBsb3RzIHRvZ2V0aGVyIHRvIGJ1aWxkIHN1YnBsb3QKc3VicGxvdChwMSwgcDIsIG5yb3dzID0gMSwgc2hhcmVYID0gRkFMU0UsIHNoYXJlWSA9IEZBTFNFKSAlPiUKICBsYXlvdXQoCiAgICB0aXRsZSA9ICJHb2FscyB2cyBTaG90cyBPdmVydmlldyIsCiAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiSG9tZSBHb2FscyIpLAogICAgeGF4aXMyID0gbGlzdCh0aXRsZSA9ICJBd2F5IEdvYWxzIiksCiAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiSG9tZSBTaG90cyIpLAogICAgeWF4aXMyID0gbGlzdCh0aXRsZSA9ICJBd2F5IFNob3RzIiksCiAgICBjb2xvcmF4aXM9bGlzdChjb2xvcnNjYWxlPSdKZXQnKQogICkKYGBgCkFuaGFuZCBkZXMgUGxvdHMgb2JlbiBpc3QgZ3V0IHp1IHNlaGVuLCBkYXNzIGRhcyBIZWltdGVhbSBvZnRtYWxzIDEtMiBUb3JlIHNjaGllc3N0IHVuZCA5LTE2IFRvcnNjaMO8c3NlIGF1ZndlaXN0LiBCZWltIEF1c3fDpHJ0c3RlYW0gc2llaHRzIGV0d2FzIGFuZGVycyBhdXM7IFNpZSBzY2hpZXNzZW4gZWhlciAwLTEgVG9yIHVuZCB3ZWlzZW4gZGFiZWkgNi0xMSBUb3JzY2jDvHNzZSBhdWYuCgpgYGB7cn0KIyBGaXQgdGhlIHJlZ3Jlc3Npb24gbW9kZWwgb2YgRnVsbHRpbWUgSG9tZSBHb2FscyBvbiBIb21lIFNob3RzCm0gPC0gbG0oRlRIRyB+IEhTLCBkYXRhID0gZGYpCgojIENyZWF0ZSB0aGUgc2NhdHRlcnBsb3Qgd2l0aCBzbW9vdGhlcgpkZiAlPiUKICBwbG90X2x5KHggPSB+SFMsIHkgPSB+RlRIRykgJT4lCiAgYWRkX21hcmtlcnMoc2hvd2xlZ2VuZCA9IEZBTFNFKSAlPiUKICBhZGRfbGluZXMoeSA9IH5maXR0ZWQobSkpICU+JQogIGxheW91dCh0aXRsZSA9ICJFeHBlY3RldCBnb2FscyBieSBob21lIHNob3RzIikKYGBgCkF1ZiBkaWVzZW0gUGxvdCwga2FubiBtYW4gYW5oYW5kIGRlciBvcmFuZ2VuIExpbmllIHNlaGVuLCB3aWV2aWVsZW4gVG9yZSBtYW4gZXJ3YXJ0ZW4ga2FubiwgYmVpIGVpbmVyIGdld2lzc2VuIEFuemFobCBTY2jDvHNzZSBkZXMgSGVpbXRlYW1zLiBadW0gQmVpc3BpZWw6IFdlbm4gZGFzIEhlaW10ZWFtIDI1IFNjaMO8c3NlIGFiZ2llYnQsIGthbm4gbWFuIGltIER1cmNoc2Nobml0dCBtaXQgMi4zMTAgVG9yZW4gcmVjaG5lbi4KCmBgYHtyfQojIEZpdCB0aGUgcmVncmVzc2lvbiBtb2RlbCBvZiBGdWxsdGltZSBBd2F5IEdvYWxzIG9uIEF3YXkgU2hvdHMKbSA8LSBsbShGVEFHIH4gQVMsIGRhdGEgPSBkZikKCiMgQ3JlYXRlIHRoZSBzY2F0dGVycGxvdCB3aXRoIHNtb290aGVyCmRmICU+JQogIHBsb3RfbHkoeCA9IH5BUywgeSA9IH5GVEFHKSAlPiUKICBhZGRfbWFya2VycyhzaG93bGVnZW5kID0gRkFMU0UpICU+JQogIGFkZF9saW5lcyh5ID0gfmZpdHRlZChtKSkgJT4lCiAgbGF5b3V0KHRpdGxlID0gIkV4cGVjdGV0IGdvYWxzIGJ5IGF3YXkgc2hvdHMiKQpgYGAKQXVmIGRpZXNlbSBQbG90LCBrYW5uIG1hbiBhbmhhbmQgZGVyIG9yYW5nZW4gTGluaWUgc2VoZW4sIHdpZXZpZWxlbiBUb3JlIG1hbiBlcndhcnRlbiBrYW5uLCBiZWkgZWluZXIgZ2V3aXNzZW4gQW56YWhsIFNjaMO8c3NlIGRlcyBBdXN3ZXJ0c3RlYW1zLiBadW0gQmVpc3BpZWw6IFdlbm4gZGFzIEF1c3dlcnRzdGVhbSAyNSBTY2jDvHNzZSBhYmdpZWJ0LCBrYW5uIG1hbiBpbSBEdXJjaHNjaG5pdHQgbWl0IDIuMzg1IFRvcmVuIHJlY2huZW4uIAoKYGBge3J9CmRmICU+JQogIHBsb3RfbHkoeCA9IH5IUywgeSA9IH5BUywgY29sb3JheGlzID0gJ2NvbG9yYXhpcycpICU+JQogIGFkZF9oaXN0b2dyYW0yZChuYmluc3ggPSA3MCwgbmJpbnN5ID0gNjApICU+JQogIGxheW91dChjb2xvcmF4aXM9bGlzdChjb2xvcnNjYWxlPSdKZXQnKSkKYGBgCkFuaGFuZCBkaWVzZXMgUGxvdHMsIHNpZWh0IG1hbiBkaWUgVmVydGVpbHVuZyBkZXIgU2NodXNzaMOkdWZpZ2tlaXQuIEluIGRlbiBhbGxlcm1laXN0ZW4gU3BpZWxlbiwgZ2ViZW4gYmVpZGUgVGVhbXMgMTAtMTUgU2Now7xzc2UgYWIuIEVzIGdpYnQgaW4gc2VsdGVuZW4gRsOkbGxlbiBhYmVyIGF1Y2ggU3BpZWxlLCB3byBkaWUgSGVpbW1hbnNjaGFmdCB2aWVsLCB2aWVsIG1laHIgU2Now7xzc2UgaGF0LiBaYiAxeCBoYXR0ZSBkYXMgSGVpbXRlYW0gMzcgU2Now7xzc2UgdW5kIGRhcyBBdXN3ZXJ0c3RlYW0gTlVSIDMhIERpZXNlcyBTcGllbCB3YXIgTGl2ZXJwb29sIDogRXZlcnRvbiBpbSBKYWhyIDIwMTYgdW5kIExpdmVycG9vbCBnZXdhbm4gNDowLiAKYGBge3J9CiNjYWxjdWxhdGUgdGhlIGVmZmljaWVuY3kgb2YgdGhlIHRlYW1zLgoKZGZfZWZmaWNpZW5jeSA8LSBkZiAlPiUKICBzdW1tYXJpc2UoCiAgICAiSG9tZSBHb2FscyBwZXIgU2hvdCIgPSByb3VuZChzdW0oRlRIRykgLyBzdW0oSFMpLGRpZ2l0cyA9IDMpLAogICAgIkhvbWUgR29hbHMgcGVyIFNob3Qgb24gVGFyZ2V0IiA9IHJvdW5kKHN1bShGVEhHKSAvIHN1bShIU1QpLGRpZ2l0cyA9IDMpLAogICAgIkF3YXkgR29hbHMgcGVyIFNob3QiID0gcm91bmQoc3VtKEZUQUcpIC8gc3VtKEFTKSxkaWdpdHMgPSAzKSwKICAgICJBd2F5IEdvYWxzIHBlciBTaG90IG9uIFRhcmdldCIgPSByb3VuZChzdW0oRlRBRykgLyBzdW0oQVNUKSxkaWdpdHMgPSAzKQopCmBgYAoKYGBge3J9CiMgVHJhbnNwb3NlIGRhdGFmcmFtZQp0X2RmX2VmZmljaWVuY3kgPC0gZGF0YS5mcmFtZSgiUGVyY2VudCIgPSB0KGRmX2VmZmljaWVuY3kpKQpgYGAKCmBgYHtyfQojIFBsb3QgdGhlIGVmZmljaWVuY3kgaW4gYSBiYXJjaGFydC4KZmlnIDwtIHBsb3RfbHkoCiAgeSA9IGMoIkhvbWUgR29hbHMgcGVyIFNob3QgIiwgIkhvbWUgR29hbHMgcGVyIFNob3Qgb24gVGFyZ2V0ICIsICJBd2F5IEdvYWxzIHBlciBTaG90ICIsICJBd2F5IEdvYWxzIHBlciBTaG90IG9uIFRhcmdldCAiKSwKICB4ID0gdF9kZl9lZmZpY2llbmN5JFBlcmNlbnQsCiAgdHlwZSA9ICJiYXIiCikKIyBOYW1lIHRoZSB0aXRsZQpmaWcgPC0gZmlnICU+JSBsYXlvdXQodGl0bGUgPSAiVGVhbSBFZmZpY2llbmN5IiwKICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIlByb2JhYmlsaXR5IikpCiMgUGxvdCBmaWd1cmUKZmlnCmBgYApBbmhhbmQgZGllc2VzIERpYWdyYW1zLCBrYW5uIG1hbiBzZWhlbiwgZGFzcyBkZXIgendlaXRlIFRlaWwgdW5zZXJlciBIeXBvdGhlc2UsIGxlaWRlciBuaWNodCBzdGltbXQuIERhcyBIZWltdGVhbSBpc3QgaW0gRHVyY2hzY2huaXR0IGVmZml6aWVudGVyIGFscyBkYXMgQXVzd2VydHN0ZWFtLiBQcm8gU2NodXNzIGF1ZnMgVG9yLCBrYW5uIGRhcyBIZWltdGVhbSBtaXQgMC4zMjggVG9yZW4gcmVjaG5lbi4gRGFzIEF1c3dlcnRzdGVhbSBrYW5uIHBybyBUb3JzY2h1c3MgbnVyIG1pdCAwLjMxMiBUb3JlbiByZWNobmVuLiAKCiMjIyBGYXppdApXaXIgc2luZCDDvGJlcnJhc2NodCwgZGFzcyBkYXMgSGVpbXRlYW0gZXR3YXMgZWZmaXppZW50ZXIgaXN0LCBhbHMgZGFzIEF1c3dlcnRzdGVhbS4gQWxsZXJkaW5ncyBpc3QgZGVyIFVudGVyc2NoaWVkIGV4dHJlbSBrbmFwLiBXYXMgYWxsZXJkaW5ncyBzcGFubmVuZCB6dSBiZW9iYWNodGVuIGlzdCwgaXN0IGRhc3MgZGFzIEhlaW10ZWFtIGltIFNjaG5pdHQgY2EuIDE0IFNjaMO8c3NlIGhhdCB1bmQgZGFzIEF1c3dlcnRzdGVhbSBudXIgY2EuIDExLiBBY2h0ZXQgZXVjaCBkb2NoIGJlaW0gbsOkY2hzdGVuIEZ1c3NiYWxsc3BpZWwgZGFyYXVmLiBJaHIga8O2bm50IHBybyBTcGllbCBhbHNvIG1pdCBjYS4gMjUgU2Now7xzc2VuIHJlY2huZW4uIERhYmVpIGlzdCBlcyB3YWhyc2NoZWlubGljaCwgZGFzcyBkYXMgSGVpbXRlYW0gZGFzIFNwaWVsIGdld2lubnQsIGF1Y2ggd2VubiB6dXIgSGFsYnplaXQgbm9jaCBlaW4gVW5lbnRzY2hpZWRlbiBzdGVodC4gCgo=